package com.itrip.log.module.db;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.itrip.log.core.BootstrapServer;
import com.itrip.log.core.IServer;
import com.itrip.log.core.ShutdownCallback;
import com.itrip.log.core.ThreadPools;

/**
 * Function:异步执行器
 *
 * @date:2016年10月20日/下午4:35:21
 * @Author:coder_czp@126.com
 * @version:1.0
 */
public class AnsySQLExecutor implements IServer, Runnable, ShutdownCallback {

	private static Logger logger = LoggerFactory.getLogger(AnsySQLExecutor.class);
	private BlockingQueue<String> sqls = new LinkedBlockingQueue<String>(2000);
	private volatile boolean isStart;
	private DaoTemplate dao;

	public void setDao(DaoTemplate dao) {
		this.dao = dao;
	}

	public void putSQL(String sql) {
		try {
			startSaveThread();
			if (sql.trim().length() > 0)
				sqls.put(sql);
		} catch (Exception e) {
			logger.error("fail to put sql to queue:" + sql, e);
		}
	}

	private void startSaveThread() {
		if (isStart == true)
			return;
		synchronized (this) {
			if (isStart == false) {
				ThreadPools.getInstance().startThread("AnsySQLExecutor", this);
				isStart = true;
			}
		}
	}

	@Override
	public void run() {
		try {
			String take = null;
			Pattern pt = Pattern.compile("Table ('\\w{1,}\\.(\\w{1,})') doesn't exist");
			Statement st = getStatement();
			while (!Thread.interrupted()) {
				try {
					take = sqls.take();
					st.executeUpdate(take);
				} catch (Exception e) {
					handleError(take, pt, st, e);
				}
			}
			st.close();
		} catch (Exception e) {
			logger.error("fail to save log", e);
		}
	}

	private void handleError(String take, Pattern pt, Statement st, Exception e) {
		Matcher c = pt.matcher(e.toString());
		if (c.find()) {
			try {
				String table = c.group(2);
				String ddl = String.format("create table if not exists %s like static_method_m1;%s", table,take);
				st.executeUpdate(ddl);
				logger.info("scuess creat {} when not exist and execute sql", table);
			} catch (Exception e1) {
				logger.error("fail to creat table not exist {}", take, e1);
			}
		} else {
			logger.error("fail to save {}", take, e);
		}
	}

	@Override
	public void onSystemExit() {
		try {
			if (sqls.size() > 0) {
				Statement st = getStatement();
				while (sqls.size() > 0) {
					st.executeUpdate(sqls.take());
				}
				st.close();
			}
		} catch (Exception e) {
			logger.error("when system exit,sqls:" + sqls, e);
		}
	}

	private Statement getStatement() throws SQLException {
		SqlSessionTemplate template = dao.getSqlSessionTemplate();
		SqlSession session = template.getSqlSessionFactory().openSession();
		Statement st = session.getConnection().createStatement();
		return st;
	}

	@Override
	public void setBoostServer(BootstrapServer server) {
		
	}

	@Override
	public void stop() {
		
	}

	@Override
	public void start() {
		
	}

}
